﻿#include "udpmulticast.h"

#include <QDebug>

namespace Common {

	UdpMulticast::UdpMulticast(QObject *parent)
		: QObject(parent)
		, m_pUdpSocket(new QUdpSocket(this))
		, m_bJoinMulticast(false)
	{
		connect(m_pUdpSocket, SIGNAL(readyRead()), this, SLOT(slotMulticastReadyRead()));
		connect(m_pUdpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
			this, SLOT(slotSocketStateChange(QAbstractSocket::SocketState)));
	}

	UdpMulticast::~UdpMulticast()
	{
		if (m_pUdpSocket != NULL)
		{
			closeMulticast();
			delete m_pUdpSocket;
			m_pUdpSocket = NULL;
		}
	}

	QUdpSocket *UdpMulticast::getUdpSocket()
	{
		return m_pUdpSocket;
	}

	bool UdpMulticast::creataMulticast(QString groupIp, int groupPort)
	{
		if (groupPort <= 0 || groupPort > USHRT_MAX || groupIp.isEmpty())
		{
			return false;
		}

		m_groupIp = QHostAddress(groupIp);
		m_groupPort = groupPort;

		// 设置缓冲区
		m_pUdpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1024 * 1024 * 8);

		// 绑定本机端口
		m_bJoinMulticast = m_pUdpSocket->bind(QHostAddress::AnyIPv4, m_groupPort, QUdpSocket::ShareAddress);
		if (m_bJoinMulticast)
		{
			m_bJoinMulticast = m_pUdpSocket->joinMulticastGroup(m_groupIp);
		}

		return m_bJoinMulticast;
	}

	bool UdpMulticast::closeMulticast()
	{
		if (!m_bJoinMulticast)
		{
			return false;
		}

		bool state = m_pUdpSocket->leaveMulticastGroup(m_groupIp);
		if (state)
		{
			m_pUdpSocket->abort();
		}
		return state;
	}

	bool UdpMulticast::sendMulticastMsg(QByteArray buff)
	{
		if (!m_bJoinMulticast)
		{
			return false;
		}

		m_pUdpSocket->writeDatagram(buff, m_groupIp, m_groupPort);
		return m_pUdpSocket->flush();
	}

	bool UdpMulticast::recvMulticastMsg(QString &sourceIp, int &sourcePort, QByteArray &message, const int replyTime)
	{
		if (!m_bJoinMulticast)
		{
			return false;
		}

		if (m_pUdpSocket->waitForReadyRead(replyTime))
		{
			while (m_pUdpSocket->hasPendingDatagrams())
			{
				QByteArray datagram;
				datagram.resize(m_pUdpSocket->pendingDatagramSize());

				QHostAddress peerAddr;
				quint16 peerPort;
				m_pUdpSocket->readDatagram(datagram.data(), datagram.size(), &peerAddr, &peerPort);

				sourceIp = peerAddr.toString();
				sourcePort = peerPort;
				message.append(datagram);
				return true;
			}
		}
		return false;
	}

	bool UdpMulticast::sendAndRecvMulticastMsg(QByteArray sendMsg, QString &sourceIp, int &sourcePort, QByteArray &recvMsg, const int replyTime)
	{
		if (sendMulticastMsg(sendMsg))
		{
			bool ret = recvMulticastMsg(sourceIp, sourcePort, recvMsg, replyTime);
			return ret;
		}
		return false;
	}

	void UdpMulticast::slotMulticastReadyRead()
	{
		while (m_pUdpSocket->hasPendingDatagrams())
		{
			QByteArray buff;
			buff.resize(m_pUdpSocket->pendingDatagramSize());

			QHostAddress peerAddr;    // 数据来源Ip
			quint16 peerPort;         // 数据来源端口
			m_pUdpSocket->readDatagram(buff.data(), buff.size(), &peerAddr, &peerPort);
			emit signalRecvMulticastMsg(peerAddr.toString(), peerPort, buff);
		}
	}

	void UdpMulticast::slotSocketStateChange(QAbstractSocket::SocketState state)
	{
		switch (state) {
		case QAbstractSocket::UnconnectedState:
		{

			break;
		}
		case QAbstractSocket::HostLookupState:
		{

			break;
		}
		case QAbstractSocket::ConnectingState:
		{

			break;
		}
		case QAbstractSocket::ConnectedState:
		{

			break;
		}
		case QAbstractSocket::BoundState:
		{

			break;
		}
		case QAbstractSocket::ClosingState:
		{

			break;
		}
		case QAbstractSocket::ListeningState:
		{

			break;
		}
		default:
			break;
		}
	}

} //namespace Core
